/*
 * ===========================================================================
 *
 *      Filename: worker_pool.c
 *   Description: implement for worker pool
 *        Author: Ye wenhao, wenhaoye@126.com
 *  Organization: 
 *
 * ===========================================================================
 */
#include "worker_pool.h"

int worker_pool_init(worker_pool_t *self, uint8_t nums)
{
    memset(self, 0, sizeof(*self));
	mutex_init(&self->lock);
    
	self->hi_worker = worker_new();
	if (!self->hi_worker) {
		worker_pool_term(self);
		return -1;
	}

    uint8_t i;
    for (i = 0; i < nums; ++i) {
        self->workers[i] = worker_new();
        if (!self->workers[i]) {
            worker_pool_term(self);
            return -1;
        }
        self->worker_nums++;
    }

    return 0;
}

int worker_pool_term(worker_pool_t *self)
{
    uint8_t i;
    uint8_t nums = self->worker_nums;
    for (i = 0; i < nums; ++i) {
        worker_destroy(&self->workers[i]);
        self->worker_nums--;
    }

	worker_destroy(&self->hi_worker);
	mutex_term(&self->lock);
    return 0;
}

static inline void worker_pool_lock(worker_pool_t *self)
{
	return mutex_get(&self->lock);
}

static inline void worker_pool_unlock(worker_pool_t *self)
{
	return mutex_put(&self->lock);
}

static worker_t *worker_pool_choose(worker_pool_t *self)
{
    if (!self || !self->worker_nums)
        return NULL;
    
    uint8_t i;
    worker_t *w = self->workers[0];
    uint32_t w_nums = worker_nums(w);
    for (i = 1; i < self->worker_nums; ++i) {
        if (worker_nums(self->workers[i]) < w_nums) {
            w = self->workers[i];
            w_nums = worker_nums(w);
        }
    }

    return w;
}

void worker_pool_add(worker_pool_t *self, work_t *w)
{
	worker_t *worker;

	worker_pool_lock(self);
	worker = worker_pool_choose(self);
	worker_add_tail(worker, w);
	worker_pool_unlock(self);
}

void worker_pool_hi_add(worker_pool_t *self, work_t *w)
{
	worker_t *p_worker;
	uint8_t ok = 0;

	worker_pool_lock(self);
	p_worker = worker_pool_choose(self);
	if (worker_nums(p_worker) == 0) {
		worker_add(p_worker, w);
		ok = 1;
	}
	worker_pool_unlock(self);

	if (ok)
		return ;
	
	worker_add(self->hi_worker, w);
	DBG("hi_worker: %u works", worker_nums(self->hi_worker));
}
